/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Control.MainControl;

import Config.ConfigCtrl;
import Data.Frontier.URLCrl;
import CrlException.CrlException;
import Config.ConfigSetting;
import Data.ActivityLog.StatisticUtility;
import DataAccessor.DatabaseAccessor;
import DataAccessor.XMLAccessor;
import Processor.ProcessControl.ProcessThreadControl;
import ExtractorInterface.ExtractorData;
import ExtractorInterface.ExtractorInterface;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 *
 * @author CUHUUHOANG
 */
public class MainControl {

    boolean isSuspended;
    boolean isStopped;
    public static ProcessThreadControl ProcessManager;
    public static ExtractorData extractorData;
    public static Constructor<? extends ExtractorInterface> ctorExtract;

    public MainControl(boolean isSuspended, boolean isStopped) {
        this.isSuspended = isSuspended;
        this.isStopped = isStopped;
    }

    public MainControl() {
        this.isSuspended = false;
        this.isStopped = false;
    }

    public void innitiate() throws CrlException {
        try {
            //load config
            XMLAccessor.ReadConfigXML();
            //set abs extractor directory
            ConfigCtrl cc= new ConfigCtrl();
            ConfigSetting.ExtractorJarFile = ConfigCtrl.getAbsPath(ConfigSetting.ExtractorJarFile);            
            //set proxy
            SetProxy();
            //create extractor and ctor
            extractorData = SetExtractorData(ConfigSetting.ExtractorJarFile);
            setExtractor(ConfigSetting.ExtractorJarFile);
            //get data from extractor to config
            cc.getDataFromExtractor(extractorData);
            //create database
            DatabaseAccessor da = new DatabaseAccessor();
            boolean databaseExist = da.TableIsExisted();
            if (databaseExist) {
                if (ConfigSetting.restartCrawling) {
                    da.DropTable();
                    da.CreateTable();
                }
            } else {
                da.CreateTable();
            }
            ///check image dir
            ConfigSetting.imageDir= ConfigCtrl.getAbsPath(ConfigSetting.imageDir);
            File parent= new File(ConfigSetting.imageDir);
            if(!parent.exists()) throw new CrlException("Image directory does not exist");
            ConfigSetting.imageDir+=extractorData.getTableName();
            File imgDir= new File(ConfigSetting.imageDir);
            if(imgDir.exists()){
                if (ConfigSetting.restartCrawling) {
                    File[] files = imgDir.listFiles();
                    if(null!=files){
                        for(int i=0; i<files.length; i++) {
                            files[i].delete();
                        }
                    }
                    imgDir.delete();
                    imgDir.mkdir();
                }
            }
            else
            {
                imgDir.mkdir();
            }
            //frontier
            URLCrl urlCrl = new URLCrl();
            urlCrl.urlDT.addURL(extractorData.getSeedURL(), 0);
            //process
            ProcessManager = new ProcessThreadControl();
            //statistic
            StatisticUtility su = new StatisticUtility();

        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }
    }

    public void startWork() throws CrlException {
        try {
            //process
            ProcessManager.start();
            //GUI work

            //timing
            StatisticUtility.setStart();
            StatisticUtility.isStopped = false;

        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }
    }

    public void suspendWork() throws CrlException {
        try {
            if (isSuspended) {
                isSuspended = false;
            } else {
                isSuspended = true;
            }
            //process
            ProcessManager.SuspendProcesses(isSuspended);
            //timing
            if (!isSuspended) {
                StatisticUtility.setStart();
                StatisticUtility.isStopped = false;
            } else {
                StatisticUtility.setStop();
                StatisticUtility.isStopped = true;
            }
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }
    }

    public void stopWork() throws CrlException {
        try {
            this.isStopped = true;
            //process
            ProcessManager.StopThead();
            //timing
            StatisticUtility.setStop();
            StatisticUtility.isStopped = true;
        } catch (Exception ex) {
            throw new CrlException(ex.getMessage());
        }
    }

    public ExtractorData SetExtractorData(String extractorPath) throws CrlException {
        ExtractorData extractor = null;
        try {
            File file = new File(extractorPath);
            URL url = file.toURL();
            URL[] urls = new URL[]{url};

            ClassLoader loader = URLClassLoader.newInstance(
                    urls,
                    getClass().getClassLoader());

            Class<?> clazz = Class.forName("CrawlerExtractor.Data", true, loader);

            Class<? extends ExtractorData> exClass = clazz.asSubclass(ExtractorData.class);

            Constructor<? extends ExtractorData> ctor = exClass.getConstructor();
            extractor = ctor.newInstance();
            return extractor;

        } catch (MalformedURLException | ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            throw new CrlException(extractorPath+" path is error"+ex.getMessage());
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }

    }

    public void setExtractor(String extractorPath) throws CrlException {
        try {
            File file = new File(extractorPath);
            URL url = file.toURL();
            URL[] urls = new URL[]{url};

            ClassLoader loader = URLClassLoader.newInstance(
                    urls,
                    getClass().getClassLoader());

            Class<?> clazz = Class.forName("CrawlerExtractor.Extractor", true, loader);

            Class<? extends ExtractorInterface> exClass = clazz.asSubclass(ExtractorInterface.class);

            ctorExtract = (Constructor<? extends ExtractorInterface>) exClass.getConstructor();

        } catch (MalformedURLException | ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalArgumentException ex) {
            throw new CrlException(ex.getMessage());
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }
    }

    public static ExtractorInterface createNewExtractor() throws CrlException {
        try {
            ExtractorInterface extractor = ctorExtract.newInstance();
            return extractor;
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            throw new CrlException(ex.getMessage());
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }
    }

    public void SetProxy() throws CrlException {
        try {
            if (ConfigSetting.useProxy) {
                System.setProperty("proxySet", "true");
                System.setProperty("proxyHost", ConfigSetting.proxyHost);
                System.setProperty("proxyPort", ConfigSetting.proxyPort);
            } else {
                System.setProperty("proxySet", "false");
                System.setProperty("proxyHost", "");
                System.setProperty("proxyPort", "");
            }
        } catch (Exception e) {
            throw new CrlException(e.getMessage());
        }
    }
}
